<?php

class getDataOsirideTask extends baseWemTask
{

    private $host;
    private $dbUser;
    private $dbPass;
    private $strNow;
    private $strLastSample;
    private $mysqli;
    private $currentOsiride_Var;
    
    static public $samOsiride_Dev = array(
        "Energy Meter"=>"tprf02_pwm",
        "Energy Meter.Subplant"=>"tprf12_gsezon",
        "Weather"=>"tprf03_met",
        "Inverter"=>"tprf04_inv",
        "String Comb"=>"tprf07_jbox",
        "MV Protection.SEB"=>"tprf08_dia4n",
        "MV Protection.ABB"=>"tprf14_abb",
        "MV Protection.Schneider"=>"tprf10_sepam",
        "MV Protection.Thytronic"=>"tprf13_thytronic");
    
    static public $samOsiride_Var = array(
        "Energy Meter"=>array("address"=>"C_PwmID",
                              "sampleTime"=>"D_TMPPerf",
                              "ActExpEn"=>"N_InstEngy_KWH",
                              "ActImpEn"=>array("N_ImpActEngyAgg_KWH","N_InstEngyCons_KWH"),
                              "Pac"=>"N_InstPwr_W",),
        
        "Energy Meter.Subplant"=>array( "address"=>"C_PwmID",
                                        "sampleTime"=>"D_TMPPerf",
                                        "ActExpEn"=>"N_InstEngy_KWH",
                                        "Pac"=>"N_InstPwr_W",),
        
        "Weather"=>array("address"=>"C_MetID",
                         "sampleTime"=>"D_TMPPerf",
                         "Irr"=>"N_TotIrr_Wsm",
                         "Tmod"=>"N_PnlTmp_C",
                         "Tenv"=>"N_ExtTmp_C",),
        
        "Inverter"=>array("address"=>"C_InvID",
                          "sampleTime"=>"D_TMPPerf",
                          "Pac"=>array("N_GridPwr_KW","N_RackOrStrGridPwr_KW"),
                          "Vac"=>"N_GridVolt_V",
                          "Vdc1"=>"N_InVolt_1_V",
                          "Pdc1"=>array("N_InPwr_1_KW","N_RackOrStrInPwr_KW"),
                          "Vdc2"=>"N_InVolt_2_V",
                          "Pdc2"=>"N_InPwr_2_KW",),
        
        "String Comb"=>array("address"=>"C_JBoxID",
                          "sampleTime"=>"D_TMPPerf",
                          "Vdc"=>"N_GlobParVolt_V",
                          "Idc"=>"N_GlobStrCurr_A",
                          "Idc1"=>"N_CurrI1_A",
                          "Idc2"=>"N_CurrI2_A",
                          "Idc3"=>"N_CurrI3_A",
                          "Idc4"=>"N_CurrI4_A",
                          "Idc5"=>"N_CurrI5_A",
                          "Idc6"=>"N_CurrI6_A",
                          "Idc7"=>"N_CurrI7_A",
                          "Idc8"=>"N_CurrI8_A",
                          "Idc9"=>"N_CurrI9_A",
                          "Idc10"=>"N_CurrI10_A",
                          "Idc11"=>"N_CurrI11_A",
                          "Idc12"=>"N_CurrI12_A"),
        
        "MV Protection.SEB"=>array("address"=>"C_Dia4nID",
                                   "sampleTime"=>"D_TMPPerf",
                                   "Vac"=>"N_VA_V",
                                   "f"=>"N_Freq_Hz"),
                
        "MV Protection.ABB"=>array("address"=>"C_ABBID",
                                   "sampleTime"=>"D_TMPPerf",
                                   "Vac12"=>"N_U12_V",
                                   "Vac23"=>"N_U23_V",
                                   "Vac31"=>"N_U31_V",
                                   "Iac"=>"N_I0_A",
                                   "f"=>"N_Freq_Hz"),
        
        "MV Protection.Schneider"=>array("address"=>"C_SepamID",
                                         "sampleTime"=>"D_TMPPerf",
                                         "Vac12"=>"N_ConcVoltU21_V",
                                         "Vac23"=>"N_ConcVoltU32_V",
                                         "Vac13"=>"N_ConcVoltU13_V",
                                         "Iac1"=>"N_CurrI1_A",
                                         "Iac2"=>"N_CurrI2_A",
                                         "Iac3"=>"N_CurrI3_A",
                                         "f"=>"N_Freq_Hz"),
        
        "MV Protection.Thytronic"=>array("address"=>"C_ThytrID",
                                         "sampleTime"=>"D_TMPPerf",
                                         "Vac"=>"N_UL1_V",
                                         "f"=>"N_Freq_Hz"),
        );
 
    public function configure()
    {
        parent::configure();
        
        $this->name      = 'getData-osiride';
        $this->briefDescription = 'Get Data from the Samares Osiride system';

        $this->dbUser="root";
        $this->dbPass="sama012009";
                
        //ARGUMENTS
        $this->addArgument('plant',  sfCommandArgument::REQUIRED,'Plant to check');
        $this->addArgument('start',  sfCommandArgument::OPTIONAL,'The starting day [Format: Y-m-d]',0);
        $this->addArgument('days',  sfCommandArgument::OPTIONAL,'Number of days to check [the greater the range the longer the script..] ',5);
    }
    public function execute($arguments = array(), $options = array())
    {   
        //DB Connection
        $this->ConnectDB();
        //register task execution
        $tasklog=seth::regTaskStart($this->name, $arguments, $options );
        
        //get the requested plant
        $plant=new Plant();
        $plant=Doctrine_Core::getTable('plant')->find($arguments['plant']);        
        if (!is_object($plant)){
            $this->logBlock("The provided plant does not exist", "ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        $plantName=$plant->getName();
        
        //add the log file
        $this->addFileLogger($plantName);
        
        //get Osiride ip adress
        $osiride=$plant->getNetDev(array("type"=>"Osiride"))->getFirst();
        if (is_object($osiride))
            $this->host=$osiride->getIp1();
        else{
            $this->logBlock("Osiride of ".$plantName." not found","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        
        /*
         * SETUP MYSQL CONNECTION
         */

        $this->logBlock("Connecting to ".$plantName." Osiride ","INFO");
        
        //TEST HOST
        if ($osiride->isPingable()){
            $opt=array();
            if ($options['debug'])
                array_push ($opt,"debug"); 
            $args=array('host'=> $this->host, "prot" => "ICMP", "iter" => 2);
            $hostIsUp=$this->runTask("wem:isUp", $args ,$opt);
            Doctrine_Core::getTable("CheckNetDev")->appendNewCheck($osiride,$hostIsUp);
            if (!$hostIsUp['isUp']){
                $this->logBlock($plantName." Osiride @".$this->host." is DOWN.\n","ERROR");
                seth::regTaskEnd($tasklog, false);
                die();
            }
        }
        
        
        //MYSQL CONNECT
        $this->mysqli = new mysqli($this->host, $this->dbUser, $this->dbPass, "osiride");
        if ($this->mysqli->connect_errno) {
            $this->logBlock("Failed to connect to MySQL: " . $this->mysqli->connect_error, "ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        
        $this->logBlock("Connected as ".$this->dbUser." to ".$plantName." Osiride MYSQL server @".$this->host, "INFO");
   
        /* 
         * TIME RANGE DEFINITION 
         */
        if ($arguments["start"]==0)
            $dStart=new DateTime();
        elseif (strtotime($arguments["start"]) == FALSE){
            $this->logBlock("Argument [start] provided is not valid. Must be a number >0","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }else
            $dStart=new DateTime($arguments["start"]);
            
        if (!is_numeric($arguments["days"]) or $arguments["days"]<=0){
            $this->logBlock("Argument [days] provided is not valid. Must be a number >0","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }else
            $days=$arguments["days"];
    
        $now=new DateTime();
        $rangeLimit=$now->sub(new DateInterval("P".$days."D"));
        $now=new DateTime();
        $this->strNow=$now->format("Y-m-d H:i:s");
        $now=new DateTime();
        $this->strLastSample=$now->sub(new DateInterval("PT15M"));
        

        /*
         *  DEVICE TO CHECK DEFINITION
         */
        $devs=$plant->getMonitoredPowerDev(array("AcqSyst"=>2));
        
        // SYNC START ON DEVICES BASE
        if ($devs->count()>0){
            
            $updateFlag=false;
            foreach ($devs as $dev){
                
              if ($options['debug'])
               echo "Mem usage is: ".(memory_get_usage()/1024)." KB \n";
               
               if (($dev->getSubtype()=="GSE") and ($dev->getSubplant()!=""))
                   $type=$dev->getType().".Subplant";
               elseif ($dev->getType()=="MV Protection")
                   $type=$dev->getType().".".$dev->getBrand();
               else
                   $type=$dev->getType();

               $table=self::$samOsiride_Dev[$type];
                
               if (isset($table)){
                    $devLastUpdate=$dev->getLastUpdate();
                    if (is_null($devLastUpdate))
                        $devLastUpdate=$rangeLimit;

                    if ($devLastUpdate<$this->strLastSample){
                        
                        $start=$devLastUpdate>$rangeLimit?$devLastUpdate->format("Y-m-d H:i:s"):$rangeLimit->format("Y-m-d H:i:s");
                        $end=$this->strNow;
                        if ($options['debug'])
                            $this->logBlock("  Updating ".$dev->getLabel()." [".$start." : ".$end."]", "INFO");

                        $updateFlag=$this->getDataByDev($table, $dev, $type, $start, $end, $options); 
                    }
                    unset($devLastUpdate);
               }
               unset($table);
               unset($type);
               $dev->free(true);
            }
            
      }else
          $this->logBlock("No device of ".$plantName." monitored by SamOsiride", "INFO");
      
        if ($options['debug'])
            $this->logBlock("Mem usage is: ",(memory_get_usage()/1024), "KB","INFO");
        
        if (!$updateFlag)
            $this->logBlock("No Updates available for ".$plant,"INFO");
        else
            $this->logBlock($plant." Updated.","INFO");
        seth::regTaskEnd($tasklog, TRUE);        
    }
    
private function getDataByDev($table, Powerdev $dev, $type, $start, $end, $options=array()){
 
                        $ts=microtime(TRUE);
                        
                        $fields=implode(",", $this->getOsirideVar($type));
                        $tmp=$this->getOsirideVar($type, "address");
                        $idField=$tmp[0];
                        $sql=" SELECT ".$fields." FROM ".$table." WHERE ".$idField."='".$dev->getAddress2()."' AND D_TMPPerf>'".$start."' AND D_TMPPerf<'".$end."' ORDER BY D_TMPPerf DESC ";
                        if ($options['debug'])
                            $this->logBlock("SQL QUERY: \n ".$sql,"INFO");
                        $result = $this->mysqli->query($sql);
                        $updateFlag=false;
                        if ($result) {
                            
                            if($result->num_rows>0){
                                $count=0;
                                while ($row = $result->fetch_assoc()) { 
                                                                   
                                    if($this->TryInsert($row,$dev,$type)){
                                        $count++;
                                        if (!$updateFlag)
                                            $updateFlag=true;
                                    }
                                }
                                if ($options['debug'])
                                    $this->logBlock("\t Inserted ".$count." records. Process took ".round((microtime(TRUE) - $ts),3)."s ", "INFO");
                            }else{
                                if ($options['debug'])
                                    $this->logBlock("\t Osiride MySQL returned Empty result set","ERROR");                         
                            }
                            
                            $result->free();
                        }else{
                            $this->logBlock("\t Query Error for .".$dev->getLabel().": \n [ERR]".$this->mysqli->error,"ERROR");
                        }
                        
                        
                        return $updateFlag;
}   
    
private function TryInsert($row, Powerdev $dev, $type){
    
    $result=false;
    $class=$dev->getVarTableName();
    $plantName=$dev->getPlant()->getName();
    $table=self::$samOsiride_Dev[$type];

    $newVar= new $class();
    $newVar->setDev($dev); 
    $newVar->setSource("osiride".$plantName.":".$table);  
                                    
    foreach ($row as $field=>$val){                                
      $wemVar=$this->getSethVar($type, $field);                
      if (($wemVar) and ($wemVar!="address")){
          
        //manage exceptions
            switch ($wemVar){
                case "Pdc1":
                    $val=($newVar->getVdc1()>0)?round(($val*1000)/$newVar->getVdc1(),3):NULL;
                    $wemVar= str_replace("P","I",$wemVar);
                    break;
                case "Pdc2":
                    $val=($newVar->getVdc2()>0)?round(($val*1000)/$newVar->getVdc2(),3):NULL;
                    $wemVar=str_replace("P","I",$wemVar);   
                    break;
            }
            $method="set".$wemVar;
            $newVar->$method($val);
        }
     }

     try{
            $newVar->save();
            $result=true;
     }catch(Doctrine_Exception $e){
         
     }
     
     $newVar->free(true);
     unset($newVar);
     
     return $result;
}

    //return an array containing all the osiride var corresponding to one or to all Seth Var
    //return array
    private function getOsirideVar($type, $var=NULL){
        
        if (!key_exists($type, self::$samOsiride_Var))
                return false;
         
         if (!isset($this->currentOsiride_Var[$type])){
             //check existence of the variables in the current version of Osiride
             $sql="SELECT `COLUMN_NAME` 
                     FROM `INFORMATION_SCHEMA`.`COLUMNS` 
                     WHERE `TABLE_SCHEMA`='osiride' AND `TABLE_NAME`='".self::$samOsiride_Dev[$type]."'";
             $result = $this->mysqli->query($sql);
             if ($result) {
                if($result->num_rows>0){
                    while ($row = $result->fetch_assoc()) {
                      $this->currentOsiride_Var[$type][]=$row['COLUMN_NAME'];
                    }
                }
             }
         }
         $devVars=self::$samOsiride_Var[$type];
         
         $osirideVar=array();
     
         foreach ($devVars as $sethVar=>$alienVar){ 
             if ( !isset($var) or ($this->varCompare($var, $sethVar))){ 
                if (is_array($alienVar)){
                    foreach ($alienVar as $alienVarEl )
                            if (array_search($alienVarEl, $this->currentOsiride_Var[$type])!== FALSE)
                                $osirideVar[]=$alienVarEl;
                }else{
                    if (array_search($alienVar, $this->currentOsiride_Var[$type])!== FALSE)
                        $osirideVar[]=$alienVar;
                } 
            }
         }
  
        return $osirideVar;  
    }
    
    //return the Seth Var corresponding to the Osiride var
    //return string
    private function getSethVar($type, $var){
        
        if (!key_exists($type, self::$samOsiride_Var))
                return false;
        
        $devVars=self::$samOsiride_Var[$type];
        
        foreach ($devVars as $sethVar=>$alienVar){
            
            if (is_array($alienVar)){
                foreach ($alienVar as $alienVarEl ){
                   
                    if ($this->varCompare($alienVarEl,$var))
                        return $sethVar;   
                }
            }else{
            
                if ($this->varCompare($alienVar,$var)){
                    return $sethVar;
                } 
            }
            
        }
        return false;

    }
    
    private function varCompare($var1, $var2){
        $var1=strtolower ($var1);
        $var2=strtolower($var2);
        
        if ($var1==$var2)
            return true;
        else 
            return false;
     
    }   
        
}


?>

